package com.eastelsoft.smartiot.bssserver.controller;

import com.eastelsoft.smartiot.bssserver.dao.*;
import com.eastelsoft.smartiot.bssserver.domain.*;
import com.eastelsoft.smartiot.bssserver.model.*;
import com.eastelsoft.smartiot.bssserver.service.*;
import com.eastelsoft.smartiot.bssserver.util.JacksonUtils;
import com.eastelsoft.smartiot.bssserver.util.MD5Encrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
@SuppressWarnings("ALL")
@RestController
@RequestMapping("/oauth2")
public class Oauth2Controller extends  AbstractController{

    @Autowired
    private RedisService redisService;
    @Autowired
    private TAppInfoService tAppInfoService;
    @Autowired
    private TUserService tuserService;
    @Autowired
    private TCmUserAccountMapper tCmUserAccountMapper;
    @Autowired
    private TAppAuthorizeService tAppAuthorizeService;
    @Autowired
    private HttpServletRequest request;
    protected Logger log = LoggerFactory.getLogger(getClass());

    /**
     *  oauth2/token接口
     * @param granttype
     * @param appid
     * @param appkey
     * @param username
     * @param password
     * @param timestamp
     * @param scope
     * @param request
     * @param response
     */
    @CrossOrigin(origins = "*")
    @RequestMapping(value = "/token",method = RequestMethod.GET)
    public @ResponseBody
    void appToken(
            @RequestParam String granttype,
            @RequestParam String appid,
            @RequestParam String appkey,
            @RequestParam String username,
            @RequestParam String password,
            @RequestParam String timestamp,
            @RequestParam String scope,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("oauth2/token(app->back_manager)[:/token?grantType="
                + granttype
                + "&appId="
                + appid
                + "&appkey="
                + appkey
                + "&username="
                + username
                + "&password="
                + password
                + "&timestamp=" + timestamp + "&scope=" + scope + "]");

        ErrorJsonBean errorJsonBean = new ErrorJsonBean();
        String callback = request.getParameter("callback");
        // 获取请求地址的ip
        String requestIp = Oauth2Controller.getIpAddr(request);
        log.info("app registet requestIp" + requestIp);
        try {
            // 业务判断
            // appId不能传空值
            if (StringUtils.isEmpty(appid)) {
                errorJsonBean.setEcode(ErrorCode.ERROR_APPID);
                errorJsonBean.setEmsg("appid为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;

            }
            // appkey不能传空值
            if (StringUtils.isEmpty(appkey)) {
                errorJsonBean.setEcode(ErrorCode.ERROR_APPID);
                errorJsonBean.setEmsg("appkey为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
                JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
            // grantType不能传空值
            if (StringUtils.isEmpty(granttype)) {
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_PARAM_MISSING));
                errorJsonBean.setEmsg("grantType为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
            // grantType只能等于password
            if (!granttype.equals("password")) {
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_PARAM_FORMAT_ERR));
                errorJsonBean.setEmsg("grantType非法");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
            if (StringUtils.isEmpty(password)) {
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_PARAM_MISSING));
                errorJsonBean.setEmsg("password为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
                JsonpPrintln(response, callback,
                        errorJsonBean);
                return;
            }
            // timestamp不能传空值
            if (StringUtils.isEmpty(timestamp)) {
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_PARAM_MISSING));
                errorJsonBean.setEmsg("timestamp为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
            // username不能传空值
            if (StringUtils.isEmpty(username)) {
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_PARAM_MISSING));
                errorJsonBean.setEmsg("username为空");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
            // 根据appid和appkey校验该app在应用表中是否存在。
            TCmAppInfo tAppInfo = tAppInfoService.findByAppIdAndAppSecret(appid,
                    appkey);
            if (tAppInfo == null) {
                errorJsonBean.setEcode(ErrorCode.ERROR_APPID_APPKEY);
                errorJsonBean.setEmsg("appid或者appkey错误");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
               JsonpPrintln(response, callback, errorJsonBean);
                return;
            }
                // 校验用户账号和密码
            TCmUserAccount tuser = tuserService.findByAcount(username);
            if (tuser==null) {
                log.info("用户名或密码错误。");
                errorJsonBean.setEcode(Integer
                        .parseInt(ErrorCode.ECODE_ACCOUNT_OR_PASSWD_ERR));
                errorJsonBean.setEmsg("帐号或密码错误");
                log.info("oauth2/token_response(back_manager->app):["
                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
                JsonpPrintln(response, callback,
                        errorJsonBean);
                return;
            }
         String checkPassword=   MD5Encrypt.MD5Encode(username+MD5Encrypt.MD5Encode(tuser.getPasswd()).toLowerCase()+timestamp).toLowerCase();
                // 用户名或密码错误。
                if (!password.equals(checkPassword)) {
                    log.info("用户名或密码错误。");
                    errorJsonBean.setEcode(Integer
                            .parseInt(ErrorCode.ECODE_ACCOUNT_OR_PASSWD_ERR));
                    errorJsonBean.setEmsg("帐号或密码错误");
                    log.info("oauth2/token_response(back_manager->app):["
                            + JacksonUtils.beanToJson(errorJsonBean) + "]");
                   JsonpPrintln(response, callback,
                            errorJsonBean);
                    return;
                }
            // 保存授权信息
            tAppAuthorizeService.saveInfo(tuser, appid, scope);
            String[] s = null;
            if (scope != null && scope.length() > 0) {
                s = scope.split(",");
            }
            // 获取授权表中的openid值
            TCmAppAuthorize tAppAuthorize = tAppAuthorizeService
                    .getByAppIDAnduserID(appid, tuser.getUserAccountId());
            // 生成accesstoken，refreshToken并且分别以accesstoken，refreshToken为key值创建redis，实现计时。
            OAuthAccessToken oAuthAccessToken = new OAuthAccessToken();
            AppTokenResponse appTokenResponse = new AppTokenResponse();
            appTokenResponse.setEmsg("成功");
                appTokenResponse.setEcode(0);
               appTokenResponse.setOpenid(tAppAuthorize.getOpenId());
               log.info("oauth2/token接口 response(back_manager->app):["
                      + JacksonUtils.beanToJson(appTokenResponse) + "]");
            JsonpPrintln(response, callback, appTokenResponse);
              return;
//            if (tAppAuthorize != null) {
//
//                String accesstoken =UUID.randomUUID().toString().replace("-", "");
//                String refreshToken = UUID.randomUUID().toString().replace("-", "");
//                appTokenResponse.setAccess_token(accesstoken);
//                appTokenResponse.setRefresh_token(refreshToken);
//                // 生成accessToken
//                oAuthAccessToken.setAppId(appid);
//                oAuthAccessToken.setCode(null);
//                oAuthAccessToken.setExpiresIn(3600 * 24 * 7);
//                oAuthAccessToken.setOpenId(tAppAuthorize.getOpenId());
//                oAuthAccessToken.setRedirectUri(null);
//                oAuthAccessToken.setRefreshToken(refreshToken);
//                oAuthAccessToken.setScope(s);
//                oAuthAccessToken.setUserId(tuser.getUserAccountId());
//                oAuthAccessToken.setUserAccount(tuser.getUserAccount());
//                log.info("oauth2/token接口 AccessToken键值对创建,value:oAuthAccessToken-"
//                        + JacksonUtils.beanToJson(oAuthAccessToken)
//                        + "tuser:"
//                        + JacksonUtils.beanToJson(tuser));
//                redisService.set(RedisKeyBuilder.buildAccessToken(accesstoken),
//                        oAuthAccessToken);
//                redisService.expire(RedisKeyBuilder.buildAccessToken(accesstoken),RedisKeyBuilder.REDIS_KEY_ACCESS_TOKEN_TIMEOUT);
//                // 生成refreshToken
//                OAuthRefressToken oAuthRefressToken = new OAuthRefressToken();
//                oAuthRefressToken.setAccessToken(accesstoken);
//                oAuthRefressToken.setAppId(appid);
//                oAuthRefressToken.setCode(null);
//                oAuthRefressToken.setExpiresIn(3600 * 24 * 180);
//                oAuthRefressToken.setOpenId(tAppAuthorize.getOpenId());
//                oAuthRefressToken.setRedirectUri(null);
//                oAuthRefressToken.setScope(s);
//                oAuthRefressToken.setUserId(tuser.getUserAccountId());
//                log.info("oauth2/token接口RefressToken键值对创建,value:oAuthRefressToken-"
//                        + JacksonUtils.beanToJson(oAuthRefressToken));
//                redisService.set(RedisKeyBuilder.buildRefreshToken(refreshToken),
//                        oAuthRefressToken);
//                redisService.expire(RedisKeyBuilder.buildRefreshToken(refreshToken),RedisKeyBuilder.REDIS_KEY_REFRESH_TOKEN_TIMEOUT);
//                appTokenResponse.setEmsg("成功");
//                appTokenResponse.setEcode(0);
////                appTokenResponse.setExpires_in(3600 * 24 * 7);
////                appTokenResponse.setOpenid(tAppAuthorize.getOpenId());
////                log.info("oauth2/token接口 response(back_manager->app):["
////                        + JacksonUtils.beanToJson(appTokenResponse) + "]");
////                JsonpPrintln(response, callback, appTokenResponse);
////                return;
//            } else {
//                errorJsonBean.setEcode(ErrorCode.ERROR_UNDINGYI);
//                errorJsonBean.setEmsg("该应用" + appid + "的用户" + tuser.getUserAccountId()
//                        + "尚未授权");
//                log.info("oauth2/token_response(back_manager->app):["
//                        + JacksonUtils.beanToJson(errorJsonBean) + "]");
//               JsonpPrintln(response, callback, errorJsonBean);
//                return;
//            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            log.error("登录token接口:", e);

        }
    }

    /**
     * oauth2/refresh_
     接口
     *
     * @param grantType
     * @param response
     */

    @RequestMapping(value = "/refresh_token")
    public @ResponseBody
    void refresh_token(
            @RequestParam(value = "grant_type", defaultValue = "") String grantType,
            @RequestParam(value = "refresh_token", defaultValue = "") String refresh_token,
            @RequestParam(value = "appid", defaultValue = "") String appId,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("oauth2/refresh_token(app->back_manager):[http://localhost:8081/oauth2/access_token?grant_type="
                + grantType

                + "&refresh_token=" + refresh_token + "&appid" + appId + "]");
        // 业务判断
        String callback = request.getParameter("callback");
        RefreshTokenResponse refreshTokenResponse = new RefreshTokenResponse();
        OAuthAccessToken oAuthAccessToken = new OAuthAccessToken();
        try {
            if (grantType == null || !grantType.equals("refresh_token")) {
                refreshTokenResponse.setEcode(ErrorCode.ERROR_UNDINGYI);
                refreshTokenResponse.setEmsg("grantType为空或非法！");
                log.info("oauth2/refresh_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(refreshTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        refreshTokenResponse);
                return;
            }
            if (StringUtils.isEmpty(refresh_token)) {
                refreshTokenResponse.setEcode(ErrorCode.ERROR_REFRESHTOKEN);
                refreshTokenResponse.setEmsg("refresh_token为空");
                log.info("oauth2/refresh_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(refreshTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        refreshTokenResponse);
                return;
            }
            if (StringUtils.isEmpty(appId)) {
                refreshTokenResponse.setEcode(ErrorCode.ERROR_APPID);
                refreshTokenResponse.setEmsg("appid为空");
                log.info("oauth2/refresh_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(refreshTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        refreshTokenResponse);
            }
            // 根据refresh_token获取oAuthRefressToken
            OAuthRefressToken  oAuthRefressToken= (OAuthRefressToken) redisService.get(RedisKeyBuilder.buildRefreshToken(refresh_token));
//            OAuthRefressToken oAuthRefressToken = redisService.get(RedisKeyBuilder.buildRefreshToken(refresh_token));
            log.info("oAuthRefressToken:"
                    + JacksonUtils.beanToJson(oAuthRefressToken));
            if (oAuthRefressToken == null) {
                refreshTokenResponse.setEcode(ErrorCode.ERROR_REFRESHTOKEN);
                refreshTokenResponse.setEmsg("refresh_token非法或已过期");
                JsonpPrintln(response, callback,
                        refreshTokenResponse);
                return;
            }

            if (!appId.equals(oAuthRefressToken.getAppId())) {
                refreshTokenResponse.setEcode(ErrorCode.ERROR_APPID);
                refreshTokenResponse.setEmsg("appid不存在");
                log.info("oauth2/refresh_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(refreshTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        refreshTokenResponse);
                return;
            }
            // 各个参数合法生成或延长队列accesstoken
            String accesstoken = oAuthRefressToken.getAccessToken();
            StringBuffer scope = new StringBuffer();
            if (oAuthRefressToken.getScope() != null
                    && oAuthRefressToken.getScope().length > 0) {
                for (String s : oAuthRefressToken.getScope()) {
                    scope.append(s + ",");
                }
            }

            // accesstoken不存在传建健值为accesstoken的队列
            if (redisService.get(RedisKeyBuilder.buildAccessToken(accesstoken)) == null) {
                TCmUserAccount tuser = tCmUserAccountMapper.selectByPrimaryKey(oAuthRefressToken
                        .getUserId());
                log.info("oauth2/refresh_token接口tuser :[ "
                        + JacksonUtils.beanToJson(tuser) + "]");
                oAuthAccessToken.setAppId(appId);
                oAuthAccessToken.setCode(oAuthRefressToken.getCode());
                oAuthAccessToken.setExpiresIn(3600 * 24 * 7);
                oAuthAccessToken.setOpenId(oAuthRefressToken.getOpenId());
                oAuthAccessToken.setRedirectUri(oAuthRefressToken
                        .getRedirectUri());
                oAuthAccessToken.setRefreshToken(refresh_token);
                oAuthAccessToken.setScope(oAuthRefressToken.getScope());
                oAuthAccessToken.setUserId(oAuthRefressToken.getUserId());
                oAuthAccessToken.setUserAccount(tuser.getUserAccount());
                accesstoken = UUID.randomUUID().toString().replace("-", "");
                redisService.set(RedisKeyBuilder.buildAccessToken(accesstoken),
                        oAuthAccessToken
                        );
                redisService.expire(RedisKeyBuilder.buildAccessToken(accesstoken),RedisKeyBuilder.REDIS_KEY_ACCESS_TOKEN_TIMEOUT);
                oAuthRefressToken.setAccessToken(accesstoken);
                log.info("oauth2/refresh_token接口oAuthAccessToken :[ "
                        + JacksonUtils.beanToJson(oAuthAccessToken) + "tuser:"
                        + JacksonUtils.beanToJson(tuser) + "]");
                // 更新refresh_token
                redisService.set(
                        RedisKeyBuilder.buildRefreshToken(refresh_token),
                        oAuthRefressToken);
                redisService.expire(RedisKeyBuilder.buildRefreshToken(refresh_token),redisService.getExpire(RedisKeyBuilder.buildRefreshToken(refresh_token)));
                //                     RedisKeyBuilder.REDIS_KEY_REFRESH_TOKEN_TIMEOUT));
            } else {
                // accesstoken已经存在 延长该队列的有效期时间
                redisService.expire(RedisKeyBuilder.buildAccessToken(accesstoken),
                        RedisKeyBuilder.REDIS_KEY_ACCESS_TOKEN_TIMEOUT);
            }
            refreshTokenResponse.setEcode(0);
            refreshTokenResponse.setEmsg("成功");
            refreshTokenResponse.setAccess_token(accesstoken);
            refreshTokenResponse.setRefresh_token(refresh_token);
            refreshTokenResponse.setExpires_in(3600 * 24 * 60);
            refreshTokenResponse.setScope(scope.toString());
            log.info("oauth2/refresh_token接口 response(wohome->app):[ "
                    + JacksonUtils.beanToJson(refreshTokenResponse) + "]");
            JsonpPrintln(response, callback, refreshTokenResponse);
            return;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * oauth2/check_token接口
     *
     * @param access_token
     * @param response
     */
    @RequestMapping(value = "/check_token")
    public @ResponseBody
    void check_token(
            @RequestParam(value = "access_token", defaultValue = "") String access_token,
            @RequestParam(value = "openid", defaultValue = "") String openId,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("oauth2/check_token(app->wohome):[http://open.wojiazongguan.cn:8080/wohome/oauth2/check_token?access_token="
                + access_token + "&openid=" + openId + "]");
        // 业务判断
        String callback = request.getParameter("callback");
        ChekTokenResponse chekTokenResponse = new ChekTokenResponse();
        try {
            if (StringUtils.isEmpty(access_token)) {
                chekTokenResponse.setEcode(ErrorCode.ERROR_ACCESSTOKEN);
                chekTokenResponse.setEmsg("access_token为空");
                log.info("oauth2/check_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(chekTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        chekTokenResponse);
                return;
            }
            // 根据refresh_token获取oAuthRefressToken
            OAuthAccessToken oAuthAccessToken = (OAuthAccessToken) redisService.get(
                    RedisKeyBuilder.buildAccessToken(access_token));

            log.info("oAuthAccessToken:"
                    + JacksonUtils.beanToJson(oAuthAccessToken));
            if (oAuthAccessToken == null) {
                chekTokenResponse.setEcode(ErrorCode.ERROR_ACCESSTOKEN);
                chekTokenResponse.setEmsg("access_token非法或已过期");
                log.info("oauth2/check_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(chekTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        chekTokenResponse);
                return;
            }
            if (StringUtils.isEmpty(openId)) {
                chekTokenResponse.setEcode(ErrorCode.ERROR_OPENID);
                chekTokenResponse.setEmsg("openid为空");
                log.info("oauth2/check_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(chekTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        chekTokenResponse);
                return;
            }
            if (!openId.equals(oAuthAccessToken.getOpenId())) {
                chekTokenResponse.setEcode(ErrorCode.ERROR_OPENID);
                chekTokenResponse.setEmsg("openid不存在");
                log.info("oauth2/check_token_response(wohome->app):["
                        + JacksonUtils.beanToJson(chekTokenResponse) + "]");
                JsonpPrintln(response, callback,
                        chekTokenResponse);
                return;
            }
            chekTokenResponse.setEcode(Integer
                    .parseInt(ErrorCode.ECODE_SUCCESS));
            chekTokenResponse.setEmsg("成功");
            chekTokenResponse.setUserAccount(oAuthAccessToken.getUserAccount());
            log.info("oauth2/check_token接口 response(wohome->app)[: "
                    + JacksonUtils.beanToJson(chekTokenResponse) + "]");
            JsonpPrintln(response, callback, chekTokenResponse);
            return;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


    /**
     * Jsonp输出
     * @param response
     * @param callback
     * @param obj
     * @throws IOException
     */
    public static void JsonpPrintln(HttpServletResponse response,
                                    String callback,Object obj) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        String jsonString = JacksonUtils.beanToJson(obj);
        if (callback!=null && !"".equals(callback)){
            jsonString = callback+"("+jsonString+")";
        }
        out.println(jsonString);
    }

}
